#include "librc522.h"

#define LOG_PRINT_DOMAIN  (0xFF00)
#include <hilog/log.h>
#define SPI_DRV_NAME "/dev/spi_rc522"

bool isrunning = false; // 线程运行标志
bool inited = false;
std::thread *readerThread; // 读取线程
CardDetectCallback callback; // 回调函数
int fd=0;
unsigned char card_buf[16];
unsigned char card_id[16];
unsigned char write_buf[2];
// 线程函数 - 持续检测卡片
void cardDetectionLoop() {
    
    
    std::stringstream oss;
    char tmpstr[100];
    int ret = 0;
    while(1){
        while(isrunning)
        {
            oss.str("");
            lseek(fd, 64*16, SEEK_SET);
            ret = read(fd, card_buf, sizeof(card_buf));
            if (ret == 0)       
            {
                sprintf(tmpstr,"Card type is : (0x%4x)\n", (card_buf[0] << 8) | card_buf[1]);
                oss <<tmpstr;
                OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "cardDetectionLoop", "%{public}s", oss.str().c_str());

                /* 获取卡片id */
                //sleep(1);
                if(card_buf[0] == 0x04 && card_buf[1] == 0x00)
                {
                    lseek(fd, 65*16, SEEK_SET);
                    ret = read(fd, card_id, sizeof(card_id));
                    if (ret == 0)       
                    {
                        if (callback) {
                            callback(card_id, 4);
                        }
                        sprintf(tmpstr,"card id is : %02x%02x%02x%02x\n", card_id[0], card_id[1], card_id[2], card_id[3]);
                        oss <<tmpstr;
                        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "cardDetectionLoop", "%{public}s", oss.str().c_str());
                        sleep(3);
                    }
                    else
                    {
                        oss <<"read cardid  failed! "<<ret;
                        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "cardDetectionLoop", "%{public}s", oss.str().c_str());
                    }
                }else
                {
                    sleep(2);
                }
                
            }
            else
            {
                sleep(2);
                oss <<"find card failed ret "<<ret;
                OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "cardDetectionLoop", "%{public}s", oss.str().c_str());
            }
        }
        usleep(1000000);
    }
    
}

int cardread_realse(){
    isrunning = false;
    close(fd);
    if(readerThread->joinable()){
        readerThread->join();
    }
    return 0;
}
int stop_cardread(){
    isrunning = false;
    return 0;
}
int start_cardread(CardDetectCallback cb,int freq){
    if(inited == true){
        isrunning = true;
        callback = cb;
    }else
    {
        card_read_init(cb,freq);
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "start_cardread", "not inited handle init");
    }

    return 0;
}
int card_read_init(CardDetectCallback cb,int freq)
{
    std::stringstream oss;
    CTL_GPIO gpio(GPIO_RST);
    int cnt = 200;

    int value[18];
    int cmd;
    int ret = 0;

    if(inited==true){
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "card_read_init", "already inited");
        return 0;
    }
    if(isrunning==true){
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "card_read_init", "already isrunning");
        return 0;
    }
    // 导出GPIO
    oss.str("");
    if (!gpio.exportGPIO()) {
        oss << "gpio rc522 rst export fail";
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "card_read_init", "%{public}s ...v1", oss.str().c_str());
        return 1;}else{
        oss << "gpio rc522 rst export ok";
    }
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "card_read_init", "%{public}s ...v1", oss.str().c_str());

    // 设置为输出模式
    oss.str("");
    if (!gpio.setDirection("out")) {
        
        oss << "gpio rc522 rst setdir fail";
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "card_read_init", "%{public}s ...v1", oss.str().c_str());
        return 1;
    }else{
        oss << "gpio rc522 rst setdir ok";
    }
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "card_read_init", "%{public}s ...v1", oss.str().c_str());

    // 高电平
    oss.str("");
    if (!gpio.setValue("1")){
        oss << "gpio rc522 rst set high fail";
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "card_read_init", "%{public}s ...v1", oss.str().c_str());
        return 1;
    } else{
        oss << "gpio rc522 rst set high ok";
    }
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "card_read_init", "%{public}s ...v1", oss.str().c_str());

    /* 打开驱动文件 */
    fd = open(SPI_DRV_NAME, O_RDWR);
    if(fd == -1){
        oss.str("");
        oss << "Can't open file " << SPI_DRV_NAME;
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "card_read_init", "%{public}s", oss.str().c_str());
        return -1;
    }
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "card_read_init", "open file %{public}s ...v1", SPI_DRV_NAME);

    isrunning = true;
    callback = cb;

    readerThread = new std::thread(cardDetectionLoop);
    readerThread->detach();
    inited = true;
    return 0;
    #if 0
    /* 设置卡片密码 */
    lseek(fd, 66*16, SEEK_SET);
    memset(card_buf, 0xFF, sizeof(card_buf));
    ret = write(fd, card_buf, sizeof(card_buf));
    if(ret < 0){
        printf("Failed to set integration time...........!\r\n");
    }
    else
    {
    	printf("set password ret %d!\r\n",ret);
    }

 
 
    
 
    /* 选择卡片 */
    //sleep(1);
    lseek(fd, 65*16, SEEK_SET);
    ret = write(fd, card_id, sizeof(card_id));
    if(ret < 0){
        printf("Failed to select card!\r\n");
    }
 
    /* 写数据 */
    //sleep(1);
    lseek(fd, 4*16, SEEK_SET);
    memset(card_buf, 0x58, sizeof(card_buf));
    ret = write(fd, card_buf, sizeof(card_buf));
    if(ret < 0){
    	printf("Failed to write card block information\r\n");
    }
 
 
    /* 获取卡片块数据 */
    //sleep(1);
    lseek(fd, 0*16, SEEK_SET);
    ret = read(fd, card_buf, sizeof(card_buf));
    if (ret == 0)       
    {
        for (int i = 0; i < 16; i++)
        {
            printf("%02x ", card_buf[i]);
        }
        printf("\r\n ");
    }
    else
    {
        printf("Failed to read card block information");
    }
 
    //sleep(1);
    close(fd);
 
    return 0;
    #endif
}
 
 
// 示例回调函数
void cardDetected(const unsigned char* uid, size_t len) {
    std::stringstream oss;
    char tmpstr[100];
    oss.str("");
    sprintf(tmpstr,"Card detected! UID:  %02x%02x%02x%02x\n", uid[0], uid[1], uid[2], uid[3]);
    oss <<tmpstr;
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "cardDetected", "%{public}s", oss.str().c_str());

    // 这里可以添加处理卡片的逻辑
}

